/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */
#ifndef PLLINKEDLISTITERATOR_H
#define PLLINKEDLISTITERATOR_H

#include <tools/PLILinkedListIterator.h>

namespace PLSDK {
    
    /**
     * The iterator for lists.
     */
    template<typename T>
    class PLLinkedListIterator {
    public:
        /**
         * Constructor.
         *
         * @param _iterator Iterator from the list.
         * @param _current The first node.
         */
        inline PLLinkedListIterator(PLILinkedListIterator<T> *_iterator, PLLinkedListNode<T> *_current) : m_current(_current), m_first(_current), m_iterator(_iterator) {}
        /**
         * Copy constructor.
         *
         * @param it The iterator to copy.
         */
        inline PLLinkedListIterator(const PLLinkedListIterator<T> &it) : m_current(m_current), m_first(it.m_first), m_iterator(it.m_iterator) {}
        /**
         * Have the current position have a next object.
         *
         * @return true if the current position have a next object.
         */
        inline bool hasNext();
        /**
         * Have the current position have a previous object.
         *
         * @return true if the current position have a previous object.
         */
        inline bool hasPrevious();
        /**
         * The next object from the list.
         *
         * @return The next object from the list.
         */
        inline T next();
        /**
         * The current object from the list.
         *
         * @return The current object from the list.
         */
        inline T current();
        /**
         * Add a object into the list at the current position.
         *
         * @param object The object to add to the list.
         */
        inline void add(T *object);
        /**
         * Remove the current object from the list.
         */
        inline void remove();
        /**
         * Reset the iterator to the first object.
         */
        inline void reset();
        /**
         * Get the current node of the iterator.
         *
         * @return The current node.
         */
        inline PLLinkedListNode<T> &currentNode();
        /**
         * Is the iterator not on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was not that position.
         */
        inline bool operator != (PLListNode<T> *node);
        /**
         * Is the iterator on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was that position.
         */
        inline bool operator == (PLListNode<T> *node);
        /**
         * Is the iterator not on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was not that position.
         */
        inline bool operator != (PLListNode<T> &node);
        /**
         * Is the iterator on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was that position.
         */
        inline bool operator == (PLListNode<T> &node);
        /**
         * * operator to get the content of the current position.
         *
         * @return The content.
         */
        inline T operator*() const;
        /**
         * Go one position forward.
         */
        inline PLLinkedListIterator<T> &operator++();
        /**
         * Go one position forward.
         */
        inline PLLinkedListIterator<T> operator++(int);
    private:
        PLLinkedListNode<T> *m_current;
        PLLinkedListNode<T> *m_first;
        PLILinkedListIterator<T> *m_iterator;
    };

    /**
     * Compare a list iterator with a list node.
     */
    template<typename T>
    bool operator != (PLLinkedListIterator<T> &it, const PLLinkedListNode<T> &node);

    /**
     * Compare a list iterator with a list node.
     */
    template<typename T>
    bool operator == (PLLinkedListIterator<T> &it, const PLLinkedListNode<T> &node);

    template<typename T>
    T PLLinkedListIterator<T>::next() {
        if(m_current != 0) {
            T o = m_iterator->next(m_current);
            m_current = static_cast<PLLinkedListNode<T> *>(m_current->next());
            return o;
        }
        return T();
    }

    template<typename T>
    T PLLinkedListIterator<T>::current() {
        return m_current->content();
    }

    template<typename T>
    PLLinkedListNode<T> &PLLinkedListIterator<T>::currentNode() {
        return *m_current;
    }

    template<typename T>
    void PLLinkedListIterator<T>::remove() {
        m_current = m_iterator->remove(m_current);
    }

    template<typename T>
    void PLLinkedListIterator<T>::reset() {
        m_current = m_first;
    }

    template<typename T>
    bool PLLinkedListIterator<T>::hasNext() {
        return m_iterator->hasNext(m_current);
    }

    template<typename T>
    bool PLLinkedListIterator<T>::hasPrevious() {
        return m_iterator->hasPrevious(m_current);
    }

    template<typename T>
    void PLLinkedListIterator<T>::add(T *object) {
        m_iterator->add(object, m_current);
        m_current = m_current->next();
    }

    template<typename T>
    bool PLLinkedListIterator<T>::operator != (PLListNode<T> *node) {
        if(m_current != node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool PLLinkedListIterator<T>::operator == (PLListNode<T> *node) {
        if(m_current == node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool PLLinkedListIterator<T>::operator != (PLListNode<T> &node) {
        if(m_current != &node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool PLLinkedListIterator<T>::operator == (PLListNode<T> &node) {
        if(m_current == &node) {
            return true;
        }
        return false;
    }

    template<typename T>
    inline T PLLinkedListIterator<T>::operator*() const {
        if(m_current->next() != 0) {
            return m_current->next()->content();
        }
        return 0;
    }

    template<typename T>
    PLLinkedListIterator<T> &PLLinkedListIterator<T>::operator++() {
        next();
        return *this;
    }

    template<typename T>
    inline PLLinkedListIterator<T> PLLinkedListIterator<T>::operator++(int) {
        PLLinkedListIterator<T> old = *this;
        next();
        return old;
    }

    template<typename T>
    bool operator != (PLLinkedListIterator<T> &it, PLLinkedListNode<T> &node) {
        if(it.currentNode() != node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool operator == (PLLinkedListIterator<T> &it, PLLinkedListNode<T> &node) {
        if(it.currentNode() == node) {
            return true;
        }
        return false;
    }

}

#endif
